<?php
/**
 * User: krisbuist
 * Date: 1/28/12
 * Time: 4:39 PM
 */

require_once(APPPATH . '/controllers/test/Toast.php');

class PostTests extends Toast
{
    function __construct()
    {
        parent::__construct(__FILE__);
        $this->clearDatabase();

        $this->postToTest = $this->createTestPost();
    }

    /**
     * @var Post
     */
    public $postToTest;

    function test_add_post()
    {
        try
        {
            $numberOfPostsBeforeInsert = (int)$this->em->createQuery('SELECT COUNT(p) FROM Post p')->getSingleScalarResult();
            $this->em->persist($this->postToTest);
            $this->em->flush();
            $numberOfPostsAfterInsert = (int)$this->em->createQuery('SELECT COUNT(p) FROM Post p')->getSingleScalarResult();

            $this->_assert_not_equals($numberOfPostsBeforeInsert, $numberOfPostsAfterInsert);
            $this->_assert_equals($numberOfPostsBeforeInsert + 1, $numberOfPostsAfterInsert);

            $this->em->flush();
        }
        catch (\Doctrine\DBAL\Query\QueryException $e)
        {
            $this->_fail('QueryException was thrown with message: <br/>' . $e->getMessage());
        }
        catch (\Doctrine\ORM\ORMException $e)
        {
            $this->_fail('ORMException was thrown with message: <br/>' . $e->getMessage());
        }
        catch (PDOException $e)
        {
            $this->_fail('PDOException was thrown with message: <br/>' . $e->getMessage());
        }
        catch (Exception $e)
        {
            $this->_fail('An Exception was thrown with message: <br/>' . $e->getMessage());
        }
    }

    /**
     * Precondition: PostToTest is inserted: test_add_post is succeeded
     */
    function test_searchPostByTitle()
    {
        $title = $this->postToTest->getTitle();
        try
        {
            $post = $this->em->getRepository('Post')->findOneBy(array('title' => $title));
            $this->_assert_not_equals($post, null);
            $this->_assert_equals($post->getTitle(), $title);
        }
        catch (\Doctrine\DBAL\Query\QueryException $e)
        {
            $this->_fail('QueryException was thrown with message: <br/>' . $e->getMessage());
        }
        catch (\Doctrine\ORM\ORMException $e)
        {
            $this->_fail('ORMException was thrown with message: <br/>' . $e->getMessage());
        }
        catch (PDOException $e)
        {
            $this->_fail('PDOException was thrown with message: <br/>' . $e->getMessage());
        }
        catch (Exception $e)
        {
            $this->_fail('An Exception was thrown with message: <br/>' . $e->getMessage());
        }
    }

    function test_changePostTitle()
    {
        try
        {
            $postToEdit = $this->em->getRepository('Post')->findOneBy(array('title' => $this->postToTest->getTitle()));
            $title = $postToEdit->getTitle();
            $newTitle = strrev($title) . $title;
            $postToEdit->setTitle($newTitle);

            $this->em->flush();

            $editedPost = $this->em->getRepository('Post')->findOneBy(array('title' => $newTitle));

            $this->_assert_equals($editedPost->getTitle(), $newTitle);
        }
        catch (Exception $e)
        {
            $this->_fail('An Exception was thrown with message: <br/>' . $e->getMessage());
        }
    }

    function test_changePostContent()
    {
        try
        {
            /**
             * @var $postToEdit Post
             */
            $postToEdit = $this->em->getRepository('Post')->findOneBy(array('title' => $this->postToTest->getTitle()));
            $content = $postToEdit->getContent();
            $content->setContent(strrev($content->getContent()) . $content->getContent());
            $postToEdit->setContent($content);

            $this->em->flush();

            $editedPost = $this->em->find('Post', $this->postToTest->getId());

            $this->_assert_equals($editedPost->getContent()->getContent(), $content->getContent());
        }
        catch (Exception $e)
        {
            $this->_fail('An Exception was thrown with message: <br/>' . $e->getMessage());
        }
    }

    function test_addPostTag()
    {
        try
        {
            /**
             * @var $post Post
             */
            $post = $this->em->find('Post', $this->postToTest->getId());
            $numberOfTags = sizeof($post->getTags());

            $newTag = new Tag();
            $newTag->setName('TestAddTag');
            $post->addTag($newTag);

            $this->em->flush();

            $editedPost = $this->em->find('Post', $this->postToTest->getId());
            $newNumberOfTags = sizeof($editedPost->getTags());

            $this->_assert_not_equals($numberOfTags, $newNumberOfTags);
            $this->_assert_equals($numberOfTags + 1, $newNumberOfTags);
        }
        catch (Exception $e)
        {
            $this->_fail('An Exception was thrown with message: <br/>' . $e->getMessage());
        }
    }

    function test_changePostCategory()
    {
        try
        {
            /**
             * @var $post Post
             */
            $post = $this->em->find('Post', $this->postToTest->getId());
            $oldCategory = $post->getCategory()->getName();

            $newCategory = new Category();
            $newCategory->setName('TestChangeCategory');
            $this->em->persist($newCategory);

            $post->setCategory($newCategory);

            $this->em->flush();

            $editedPost = $this->em->find('Post', $post->getId());

            $this->_assert_not_equals($oldCategory, $editedPost->getCategory()->getName());

        }
        catch (Exception $e)
        {
            $this->_fail('An Exception was thrown with message: <br/>' . $e->getMessage());
        }
    }

    function test_removePost()
    {
        try
        {
            $numberOfPostsBeforeRemove = (int)$this->em->createQuery('SELECT COUNT(p) FROM Post p')->getSingleScalarResult();
            /**
             * @var $postToDelete Post
             */
            $postToDelete = $this->em->find('Post', $this->postToTest->getId());
            $this->em->remove($postToDelete);
            $this->em->flush();
            $numberOfPostsAfterRemove = (int)$this->em->createQuery('SELECT COUNT(p) FROM Post p')->getSingleScalarResult();

            $this->_assert_not_equals($numberOfPostsBeforeRemove, $numberOfPostsAfterRemove);
            $this->_assert_equals($numberOfPostsBeforeRemove-1, $numberOfPostsAfterRemove);

        }
        catch (Exception $e)
        {
            $this->_fail('An Exception was thrown with message: <br/>' . $e->getMessage());
        }
    }

    private function clearDatabase()
    {
        $connection = $this->em->getConnection();
        $platform = $connection->getDatabasePlatform();

        $connection->executeUpdate($platform->getTruncateTableSQL('post', true));
        $connection->executeUpdate($platform->getTruncateTableSQL('post_content', true));
        $connection->executeUpdate($platform->getTruncateTableSQL('post_tag', true));
        $connection->executeUpdate($platform->getTruncateTableSQL('tag', true));
        $connection->executeUpdate($platform->getTruncateTableSQL('category', true));
        $connection->executeUpdate($platform->getTruncateTableSQL('user', true));
        $connection->executeUpdate($platform->getTruncateTableSQL('account_type', true));
    }

    /**
     * @return Post
     */
    public function createTestPost()
    {
        $post = new Post();

        try
        {
            $post->setAuthor($this->getTestUser());
            $post->setCategory($this->getTestCategory());

            $tags = $this->getTestTags(5);
            foreach ($tags as $tag)
            {
                $post->addTag($tag);
            }

            $post->setContent($this->getTestPostContent());
            $post->setTitle('TestTitle');
        }
        catch (\Doctrine\ORM\ORMException $e)
        {

        }
        catch (PDOException $e)
        {

        }

        return $post;
    }

    /**
     * @return User
     */
    private function getTestUser()
    {
        $user = new User();
        $user->setBankAccount('1234567890');
        $user->setEmail('test@nieuwsbuis');
        $user->setGender('m');
        $user->setName('Unit Test');
        $user->setType($this->getTestAccount());
        $user->setUsername('tester');
        $user->setPassword(sha1('tester'));

        $this->em->persist($user);
        return $user;
    }

    /**
     * @return Category
     */
    private function getTestCategory()
    {
        $category = new Category();
        $category->setName('TestCategory');
        $this->em->persist($category);
        return $category;
    }


    /**
     * @param $numberOfTags int
     * @return array
     */
    private function getTestTags($numberOfTags)
    {
        $tags = array();
        for ($i = 1; $i <= $numberOfTags; $i++)
        {
            $tag = new Tag();
            $tag->setName('Tag' . $i);
            $tags[] = $tag;
        }
        return $tags;
    }

    /**
     * @return Account_Type
     */
    private function getTestAccount()
    {
        $accountType = new Account_Type();
        $accountType->setName('TestAccount');
        $accountType->setAccessLevel(1);
        $this->em->persist($accountType);
        return $accountType;
    }

    /**
     * @return Post_Content
     */
    private function getTestPostContent()
    {
        $content = new Post_Content();
        $content->setContent('TestContent');
        return $content;
    }
}
